﻿Imports System.Reflection
Imports System.Reflection.Emit
Imports VBParser

Namespace Compiler.Semantic

    Public Class TypeParameterDescription
        Inherits TypeDescription

        Public Sub New(ByVal parent As GenericTypeDescription, ByVal syntaxNode As TypeParameter)
            MyBase.New(parent)
            Debug.Assert(syntaxNode IsNot Nothing)

            m_typeParamSyntaxNode = syntaxNode
        End Sub

        Private m_typeParamSyntaxNode As TypeParameter
        Public Overrides Property SyntaxNode() As VBParser.Tree
            Get
                Return m_typeParamSyntaxNode
            End Get
            Set(ByVal value As VBParser.Tree)
                m_typeParamSyntaxNode = TryCast(value, TypeParameter)
            End Set
        End Property

        Private m_typeParamBuilder As GenericTypeParameterBuilder
        Public Overrides Property UnderlyingType() As System.Type
            Get
                Return m_typeParamBuilder
            End Get
            Set(ByVal value As System.Type)
                m_typeParamBuilder = TryCast(value, GenericTypeParameterBuilder)
            End Set
        End Property

        Private m_TypeConstraints As List(Of TypeReference)
        Public ReadOnly Property TypeConstraints() As IList(Of TypeReference)
            Get
                Return m_TypeConstraints
            End Get
        End Property

        Public Overrides Function SearchChild(ByVal childBinder As Binder) As NameContainer
            'type parameter can't have children
            Return Nothing
        End Function

        ''' <summary>
        ''' Try parse the syntax node and generate name and host type information.
        ''' </summary>
        ''' <returns>True if no exception occured.</returns>
        Public Overrides Function DeclareSyntaxNode() As Boolean
            'get name of the type paramter
            Name = Symbol.Get(m_typeParamSyntaxNode.TypeName.Name)

            Stage = SemanticStage.Declared
            Return True
        End Function
    End Class

    Public MustInherit Class GenericTypeDescription
        Inherits TypeDescription

        'class specified contents

        Private m_typeParameters As BindingTable(Of TypeDescription)

        Protected Sub New(ByVal parent As NameContainer, ByVal genericParameterList As BindingTable(Of TypeDescription))
            MyBase.New(parent)

            Debug.Assert(genericParameterList IsNot Nothing)
            m_typeParameters = genericParameterList
        End Sub

        Public Overrides ReadOnly Property IdentifyBinder() As Binder
            Get
                Return New TypeDeclBinder(Name, TypeParameters.Count)
            End Get
        End Property

        Protected Sub New(ByVal parent As NameContainer)
            MyClass.New(parent, New BindingTable(Of TypeDescription))
        End Sub

        Public ReadOnly Property TypeParameters() As BindingTable(Of TypeDescription)
            Get
                Return m_typeParameters
            End Get
        End Property

        Public ReadOnly Property IsGeneric() As Boolean
            Get
                Return m_typeParameters.Count > 0
            End Get
        End Property

        Public Overrides Function SearchChild(ByVal childBinder As Binder) As NameContainer
            'Search parameter list
            Dim genericParam As TypeDescription = Nothing
            If TypeParameters.TryLookUp(childBinder, genericParam) Then
                Return genericParam
            End If

            'not found, try search base
            Return MyBase.SearchChild(childBinder)
        End Function

        ''' <summary>
        ''' Create description of a type parameter declaration. The constraint should be resolved later.
        ''' </summary>
        ''' <param name="syntaxNode"></param>
        ''' <returns>True if the declaration finished successfully with no error. Otherwise false.</returns>
        Public Function DeclareTypeParameter(ByVal syntaxNode As TypeParameter) As Boolean

            Dim typeParamDesc As New TypeParameterDescription(Me, syntaxNode)
            Dim succFlag As Boolean = typeParamDesc.DeclareSyntaxNode()

            If Not m_typeParameters.Enter(New TypeDeclBinder(typeParamDesc.Name, 0), typeParamDesc) Then
                'Add semantic error
                CompileUnit.SemanticErrorList.Add( _
                    New SemanticError(SemanticErrorType.TypeParameterRedefined, syntaxNode.Span, typeParamDesc.Name))
                succFlag = False
            End If

            Return succFlag
        End Function
    End Class
End Namespace